﻿/**********************************************************************************
 * Project Name :   
 * Remarks      :  
 * Class Name   :  AssertCommon 
 * Version      :  v1.0.0.0 
 * Author       :  Joey Liang 
 * Description  : 
 * Created Time :  2013/10/16 21:41:08
 * Update Man   :  Joey Liang
 * Update Time  :  2013/10/16 21:41:08
************************************************************************/

using System;

namespace IdleTest.MSTest
{
    /// <summary>
    /// (不应对此文件发生任何修改，应在AssertCommon_Editable.cs中添加或修改)
    /// 断言类，该类将不依赖于所使用的单元测试框架，可使用任何C#测试框架，只需实现IAssertInstance接口，
    /// 并调用RegisterInstance将实现的IAssertInstance接口类型注册即可
    /// </summary>
    public partial class AssertCommon
    {
        #region 断言实例IAssertInstance

        static IAssertInstance instance;

        /// <summary>
        /// 获取或设置断言实例
        /// </summary>
        public static IAssertInstance AssertInstance
        {
            set { instance = value; }
            get
            {
                if (instance == null)
                {
                    instance = DEFAULT_INSTANCE;
                }
                return instance;
            }
        }

        /// <summary>
        /// 重新设置IAssertInstance实例或重置为置为默认实例（传空值或不传参数）
        /// </summary>
        public static void ResetAssertInsance(IAssertInstance assertInstance = null)
        {
            if (assertInstance == null)
            {
                instance = DEFAULT_INSTANCE;
            }
            else
            {
                instance = assertInstance;
            }
        }

        #endregion

        #region 主方法

        /// <summary>
        /// 断言使用相等运算符验证指定的两个泛型数据是否相等。
        /// </summary>
        /// <typeparam name="T">类型参数</typeparam>
        /// <param name="expected">要比较的第一个泛型类型数据。 这是单元测试要求的泛型类型数据。</param>
        /// <param name="actual">要比较的第二个泛型类型数据。 这是单元测试生成的泛型类型数据。</param>
        /// <param name="areEqual">断言是否相等</param>
        public static void AreEqual<T>(T expected, T actual, bool areEqual = true)
        {
            AssertInstance.AreEqual<T>(expected, actual, areEqual);
        }

        /// <summary>
        /// 断言为null
        /// </summary>
        /// <param name="actuals">需要断言的对象</param>
        /// <param name="isNull">是否断言为空</param>
        public static void IsNull<T>(bool isNull = true, params T[] actuals)
        {
            ForeachHandle<T>(actuals, (T obj) =>
            {
                AssertInstance.IsNull<T>(obj, isNull);
            });
        }

        /// <summary>
        /// 断言为空或null
        /// </summary>
        /// <typeparam name="T">类型参数</typeparam>
        /// <param name="actual">实际值</param>
        /// <param name="isEmpty">是否断言为空</param>
        public static void IsEmpty<T>(T actual, bool isEmpty = true)
        {
            AssertInstance.IsEmpty<T>(actual, isEmpty);
        }

        /// <summary>
        /// 断言是否是某一类型
        /// </summary>
        /// <param name="expectedType">预期类型</param>
        /// <param name="actuals">需要断言的对象</param>
        public static void IsInstance(Type expectedType, params object[] actuals)
        {
            ForeachHandle<object>(actuals, (object obj) =>
            {
                AssertInstance.IsInstance(expectedType, obj);
            });
        }

        /// <summary>
        /// 断言为true或false
        /// </summary>
        /// <param name="isTrue">是否为True</param>
        /// <param name="actuals">断言的值</param>
        public static void IsBoolean(bool isTrue = true, params bool[] actuals)
        {
            ForeachHandle<bool>(actuals, p => AssertInstance.IsBoolean(p, isTrue));
        }

        /// <summary>
        /// 断言调用一个函数是否抛出异常
        /// </summary>
        /// <param name="hasThrow">断言是否抛出异常</param>
        /// <param name="actions">执行的函数集</param>        
        public static void ThrowException(bool hasThrow = true, params Action[] actions)
        {
            ForeachHandle<Action>(actions, p => AssertInstance.ThrowException(p, hasThrow));
        }

        #endregion

        #region AreEqual方法的重载
        /// <summary>
        /// 断言使用相等运算符验证指定的泛型集合数据是否与给定预期值相等。
        /// </summary>
        /// <typeparam name="T">类型参数</typeparam>
        /// <param name="expected">要比较的第一个泛型类型数据。 这是单元测试要求的泛型类型数据。</param>
        /// <param name="areEqual">断言是否相等</param>
        /// <param name="actuals">要比较的第二个泛型类型数据集合。 这是单元测试生成的泛型类型数据。</param>
        public static void AreEqual<T>(
            T expected, bool areEqual = true, params T[] actuals)
        {
            ForeachHandle<T>(actuals, (T obj) => { AreEqual<T>(expected, obj, areEqual); });
        }

        ///// <summary>
        ///// 断言使用相等运算符验证指定的泛型集合数据是否与给定预期值相等。
        ///// </summary>
        ///// <typeparam name="T">类型参数</typeparam>
        ///// <param name="expected">要比较的第一个泛型类型数据。 这是单元测试要求的泛型类型数据。</param>
        ///// <param name="actuals">要比较的第二个泛型类型数据。 这是单元测试生成的泛型类型数据。
        ///// 其中key为是否断言相等，value为要比较的具体数据</param>
        //public static void AssertEqual<T>(
        //    T expected, Dictionary<bool, T> actuals)
        //{
        //    ForeachHandle<KeyValuePair<bool, T>>(actuals.ToArray(), (KeyValuePair<bool, T> obj) =>
        //    {
        //        AssertEqual<T>(expected, obj.Value, obj.Key);
        //    });
        //}

        ///// <summary>
        ///// 断言使用相等运算符验证指定的泛型集合数据是否相等。
        ///// </summary>
        ///// <typeparam name="T">类型参数</typeparam>
        ///// <param name="asserts">需要断言的键值对集合，其中bool键为断言是否相等；
        ///// Value子值中的key为要比较的第一个泛型类型数据，这是单元测试要求的泛型类型数据；
        ///// Value子值中的key为要比较的第二个泛型类型数据，这是单元测试生成的泛型类型数据。</param>
        //public static void AssertEqual<T>(Dictionary<bool, KeyValuePair<T, T>> asserts)
        //{
        //    ForeachHandle<KeyValuePair<bool, KeyValuePair<T, T>>>(asserts.ToArray(), 
        //        (KeyValuePair<bool, KeyValuePair<T, T>> obj) =>
        //    {
        //        AssertEqual<T>(obj.Value.Key, obj.Value.Value, obj.Key);
        //    });
        //}

        /// <summary>
        /// 断言相等
        /// </summary>
        /// <typeparam name="TParameter">方法参数类型</typeparam>
        /// <typeparam name="TReturn">方法返回类型</typeparam>
        /// <param name="expected">预期值</param>
        /// <param name="args">需断言的参数集</param>
        /// <param name="areEqual">是否断言相等</param>
        /// <param name="funcs">测试的方法集合</param>
        public static void AreEqual<TParameter, TReturn>(TReturn expected,
            TParameter[] args, bool areEqual = true, params Func<TParameter, TReturn>[] funcs)
        {
            AssertHandle<TParameter, TReturn>((TReturn actual) =>
            {
                AreEqual<TReturn>(expected, actual, areEqual);
            }, args, funcs);
        }

        /// <summary>
        /// 断言相等
        /// </summary>
        /// <typeparam name="TParameter1">方法参数类型1</typeparam>
        /// <typeparam name="TParameter2">方法参数类型2</typeparam>
        /// <typeparam name="TReturn">方法返回类型</typeparam>
        /// <param name="expected">预期值</param>
        /// <param name="args1">需断言的参数集1</param>
        /// <param name="args2">需断言的参数集1</param>
        /// <param name="areEqual">是否断言相等</param>
        /// <param name="funcs">测试的方法集合</param>
        public static void AreEqual<TParameter1, TParameter2, TReturn>(
            TReturn expected, TParameter1[] args1, TParameter2[] args2, bool areEqual = true,
            params Func<TParameter1, TParameter2, TReturn>[] funcs)
        {
            AssertHandle<TParameter1, TParameter2, TReturn>((TReturn actual) =>
            {
                AreEqual<TReturn>(expected, actual, areEqual);
            }, args1, args2, funcs);
        }

        #endregion

        #region IsNull 重载

        /// <summary>
        /// 断言为null
        /// </summary>
        /// <typeparam name="TParameter">方法参数类型</typeparam>
        /// <typeparam name="TReturn">方法返回类型</typeparam>
        /// <param name="action">调用的方法</param>
        /// <param name="args">需断言的参数集</param>
        /// <param name="funcs">测试的方法集合</param>
        /// <param name="isNull">是否断言为空</param>
        public static void IsNull<TParameter, TReturn>(
            TParameter[] args, bool isNull = true, params Func<TParameter, TReturn>[] funcs)
        {
            AssertHandle<TParameter, TReturn>((TReturn actual) =>
            {
                IsNull<TReturn>(isNull, actual);
            }, args, funcs);
        }

        /// <summary>
        /// 断言为null
        /// </summary>
        /// <typeparam name="TParameter1">方法参数类型</typeparam>
        /// <typeparam name="TParameter2">方法参数类型</typeparam>
        /// <typeparam name="TReturn">方法返回类型</typeparam>
        /// <param name="action">调用的方法</param>
        /// <param name="args1">需断言的参数集</param>
        /// <param name="args2">需断言的参数集</param>
        /// <param name="isNull">是否断言为空</param>
        /// <param name="funcs">测试的方法集合</param>
        public static void IsNull<TParameter1, TParameter2, TReturn>(
            TParameter1[] args1, TParameter2[] args2, bool isNull = true,
            params Func<TParameter1, TParameter2, TReturn>[] funcs)
        {
            AssertHandle<TParameter1, TParameter2, TReturn>((TReturn actual) =>
            {
                IsNull<TReturn>(isNull, actual);
            }, args1, args2, funcs);
        }

        #endregion

        #region AssertEmpty 重载
        /// <summary>
        /// 断言为Empty
        /// </summary>
        /// <typeparam name="TParameter">方法参数类型</typeparam>
        /// <typeparam name="TReturn">方法返回类型</typeparam>
        /// <param name="action">调用的方法</param>
        /// <param name="args">需断言的参数集</param>
        /// <param name="funcs">测试的方法集合</param>
        /// <param name="assertNull">是否断言为空</param>
        public static void IsEmpty<TParameter, TReturn>(
            TParameter[] args, bool isEmpty = true, params Func<TParameter, TReturn>[] funcs)
        {
            AssertHandle<TParameter, TReturn>((TReturn actual) =>
            {
                IsEmpty<TReturn>(actual, isEmpty);
            }, args, funcs);
        }

        /// <summary>
        /// 断言为Empty
        /// </summary>
        /// <typeparam name="TParameter1">方法参数类型</typeparam>
        /// <typeparam name="TReturn">方法返回类型</typeparam>
        /// <param name="action">调用的方法</param>
        /// <param name="args1">需断言的参数集</param>
        /// <param name="funcs">测试的方法集合</param>
        /// <param name="assertNull">是否断言为空</param>
        public static void IsEmpty<TParameter1, TParameter2, TReturn>(
            TParameter1[] args1, TParameter2[] args2,
            bool isEmpty = true,
            params Func<TParameter1, TParameter2, TReturn>[] funcs)
        {
            AssertHandle<TParameter1, TParameter2, TReturn>((TReturn actual) =>
            {
                IsEmpty<TReturn>(actual, isEmpty);
            }, args1, args2, funcs);
        }

        #endregion

        #region AssertBoolean重载
        /// <summary>
        /// 断言为true或false
        /// </summary>
        /// <typeparam name="TParameter">参数类型</typeparam>
        /// <param name="args">参数集</param>
        /// <param name="isTrue">是否为True</param>
        /// <param name="funcs">测试的方法集</param>
        public static void IsBoolean<TParameter>(
            TParameter[] args, bool isTrue = true, params Func<TParameter, bool>[] funcs)
        {
            AssertHandle<TParameter, bool>(p => IsBoolean(isTrue, p), args, funcs);
        }

        /// <summary>
        /// 断言为true或false
        /// </summary>
        /// <typeparam name="TParameter1">参数类型1</typeparam>
        /// <typeparam name="TParameter2">参数类型2</typeparam>
        /// <param name="args1">参数集1</param>
        /// <param name="args2">参数集2</param>
        /// <param name="isTrue">是否为True</param>
        /// <param name="funcs">测试的方法集</param>
        public static void IsBoolean<TParameter1, TParameter2>(TParameter1[] args1,
            TParameter2[] args2, bool isTrue = true, params Func<TParameter1, TParameter2, bool>[] funcs)
        {
            AssertHandle<TParameter1, TParameter2, bool>(p => IsBoolean(isTrue, p), args1, args2, funcs);
        }
        #endregion

        #region ThrowException重载
        /// <summary>
        /// 断言调用一个函数是否抛出异常
        /// </summary>
        /// <typeparam name="TParameter">参数类型</typeparam>
        /// <param name="args">参数集</param>
        /// <param name="hasThrow">断言是否抛出异常</param>
        /// <param name="actions">测试的方法集</param>
        public static void ThrowException<TParameter>(TParameter[] args, bool hasThrow = true, params Action<TParameter>[] actions)
        {
            ForeachHandle<TParameter>(args,
                p => ForeachHandle<Action<TParameter>>(actions, o => ThrowException(hasThrow, () => o(p)))
                );
        }

        /// <summary>
        /// 断言调用一个函数是否抛出异常
        /// </summary>
        /// <typeparam name="TParameter1">参数类型1</typeparam>
        /// <typeparam name="TParameter2">参数类型2</typeparam>
        /// <param name="args1">参数集1</param>
        /// <param name="args2">参数集2</param>
        /// <param name="hasThrow">是否抛出异常</param>
        /// <param name="actions">测试的方法集</param>
        public static void ThrowException<TParameter1, TParameter2>(TParameter1[] args1, TParameter2[] args2, bool hasThrow = true, params Action<TParameter1, TParameter2>[] actions)
        {
            ForeachHandle<TParameter1>(args1, p1 => ForeachHandle<TParameter2>(args2,
                    p2 => ForeachHandle<Action<TParameter1, TParameter2>>(
                        actions, o => ThrowException(hasThrow, () => o(p1, p2)))
                ));
        }
        #endregion

        #region 断言通用
        /// <summary>
        /// 多个断言进行
        /// </summary>
        /// <typeparam name="TParameter">方法参数类型</typeparam>
        /// <typeparam name="TReturn">方法返回类型</typeparam>
        /// <param name="funcs">测试的方法集合</param>
        /// <param name="assertAction">调用的断言方法</param>
        /// <param name="args">需断言的参数集</param>
        public static void AssertHandle<TParameter, TReturn>(
            Action<TReturn> assertAction, TParameter[] args, params Func<TParameter, TReturn>[] funcs)
        {
            ForeachHandle<Func<TParameter, TReturn>>(funcs, (Func<TParameter, TReturn> func) =>
            {
                ForeachHandle<TParameter>(args, (TParameter param) =>
                {
                    assertAction(func(param));
                });
            });
        }

        /// <summary>
        /// 多个断言进行
        /// </summary>
        /// <typeparam name="TParameter1">方法参数类型1</typeparam>
        /// <typeparam name="TParameter2">方法参数类型2</typeparam>
        /// <typeparam name="TReturn">方法返回类型</typeparam>
        /// <param name="funcs">测试的方法集合</param>
        /// <param name="assertAction">调用的断言方法</param>
        /// <param name="args1">需断言的参数集1</param>
        /// <param name="args2">需断言的参数集1</param>
        public static void AssertHandle<TParameter1, TParameter2, TReturn>(
            Action<TReturn> assertAction, TParameter1[] args1, TParameter2[] args2,
            params Func<TParameter1, TParameter2, TReturn>[] funcs)
        {
            ForeachHandle<Func<TParameter1, TParameter2, TReturn>>(funcs,
                (Func<TParameter1, TParameter2, TReturn> func) =>
                {
                    ForeachHandle<TParameter1, TParameter2>(args1, args2,
                        (TParameter1 param1, TParameter2 param2) =>
                        {
                            assertAction(func(param1, param2));
                        });
                });
        }
        #endregion

        #region 外部依赖
        /// <summary>
        /// 对数组执行简单遍历
        /// </summary>
        /// <typeparam name="T">数组类型</typeparam>
        /// <param name="array">需要遍历的数组</param>
        /// <param name="action">遍历每一项所需执行的委托</param>
        public static void ForeachHandle<T>(Array array, Action<T> action, int loopCount = 1)
        {
            TestCommon.ForeachHandle<T>(array, action, loopCount);
        }

        /// <summary>
        /// 对两个数组执行简单交叉遍历
        /// </summary>
        /// <typeparam name="T1">第一个数组类型</typeparam>
        /// <param name="array1">需要遍历的第一个数组</param>
        /// <typeparam name="T2">第二个数组类型</typeparam>
        /// <param name="array2">需要遍历的第二个数组</param>
        /// <param name="action">交叉遍历每一项所需执行的委托</param>
        public static void ForeachHandle<T1, T2>(T1[] array1, T2[] array2, Action<T1, T2> action)
        {
            TestCommon.ForeachHandle<T1, T2>(array1, array2, action);
        }

        #endregion
    }
}
